# proevolytx@gmail.com
# 2012/10/1

from lexer import *
from copy import deepcopy

class PreParser:
    def __init__(s, lex):
        s.lex = lex

    # Program -> Statements*
    def Program(s):
        result = []
        while s.lex.Peek()["type"] != "none":
            result += s.Statement()
        return result

    # Statement -> space? (newline | none)
    # output: nothing
    #
    # Statement -> (space? Factor space?)* (newline | none)
    # output:
    #     space before the first Factor will be convert to indent(space)
    #     if no space is before the first Factor, we generate indent(0)
    #     other spaces will be omitted
    #     finally we generate a newline after each statement
    def Statement(s):
        first = s.lex.Peek()
        if first["type"] == "space":
            s.lex.Next()
        else:
            first = {"type":"space", "space":0, "line":first["line"]}

        result = []
        while True:
            peek = s.lex.Peek()
            if peek["type"] in ["newline", "none"]:
                s.lex.Next()
                result.append({"type":"newline", "line":peek["line"]})
                break
            result += s.Factor()

        if result[0]["type"] != "newline":
            indent = {"type":"indent",
                      "indent":first["space"],
                      "line":first["line"]}
            return [indent] + result
        else:
            return []

    brackets = {"(":")", "[":"]", "{":"}"}

    # Factor -> non-space and non-left-bracket tokens
    # output: the token
    # Factor -> left-bracket Inner* coresponding-right-bracket
    # Inner -> space-or-newline? Factor space-or-newline?
    # output:
    #     brackets and non-space elements is outputed
    #     newlines in brackets will not be outputed
    def Factor(s):
        peek = s.lex.Peek()
        
        if peek["type"] == "keyword" and \
           peek["content"] in PreParser.brackets:
            left = peek["content"]
            result = [peek]
            s.lex.Next()
            
            while True:
                peek = s.lex.Peek()
                if peek["type"] == "keyword" and \
                   peek["content"] == PreParser.brackets[left]:
                    result.append(peek)
                    s.lex.Next()
                    break
                elif peek["type"] == "newline":
                    s.lex.Next()
                    continue
                elif peek["type"] == "none":
                    raise Exception("Unmatched brackets : " + left)
                else:
                    result += s.Factor()
            return result
        
        else:
            s.lex.Next()
            if peek["type"] == "keyword" and \
               peek["content"] in PreParser.brackets.values():
                raise Exception("Unmatched brackets : " + peek["content"])

            if peek["type"] == "space":
                return []
            else:
                return [peek]

if __name__ == "__main__":
    print "running..."
    fs = FileStream("test/test5.py")
    lex = Lexer()
    lex.SetStream(fs)
    preparser = PreParser(lex)
    result = preparser.Program()
    print str(len(result)), "tokens"

    line = None
    for r in result:
        if r["line"] != line:
            line = r["line"]
            print ""
        print r,
